#ifndef TCmdArgs_h__
#define TCmdArgs_h__


namespace inf {

    // ==============================================================================
    //! Console command arguments
    // ==============================================================================
    template <typename Type>
    class TCmdArgs : public TStrList<Type> {
    public:
        // ==============================================================================
        //! Constructor
        //!
        //! @param	str	The string to tokenize
        // ==============================================================================
        TCmdArgs( const Type* str =NULL ) : TStrList<Type>(16) { if ( str ) TokenizeString( str ); }

        ~TCmdArgs( void ) { this->clear(); }
        // ==============================================================================
        //! Get the number of arguments
        //!
        //! @return	Number of arguments found
        // ==============================================================================
        int					Argc( void ) const { return this->num; }

        // ==============================================================================
        //! Get the nth argument
        //!
        //! @param	i	The index
        //!
        //! @return	NULL if it fails, else a pointer to the nth argument
        // ==============================================================================
        const Type *		Argv( int i ) const;

        // ==============================================================================
        //! Parse a string for arguments
        //!
        //! @param	str	The string to parse
        // ==============================================================================
        void				TokenizeString( const Type* text );

    private:
        static const int	MAX_CMD_ARGUMENTS	= 64;	//!< The maximum number of command arguments
        static const int	MAX_CMD_STRING		= 2048;	//!< The maximum number of bytes one argument can hold
    };
    //! @}

    template <typename Type>
    const Type* TCmdArgs<Type>::Argv( int i ) const {
        assert( i>=0 && i<num );
        return this->list[i].c_str();
    }

    template <typename Type>
    bool TIsSpace(const Type c) {
        using namespace inf;
        return c == ConstChar<Type>::WhiteSpace
            || c == ConstChar<Type>::Formfeed
            || c == ConstChar<Type>::NewLine
            || c == ConstChar<Type>::Return 
            || c == ConstChar<Type>::Table 
            || c == ConstChar<Type>::VerticalTable 
            || c == (unsigned char)0x0D || c == (unsigned char)0x0A;
    }

    template <typename Type>
    void TCmdArgs<Type>::TokenizeString( const Type* text ) {
        using namespace inf;

        int bufPos = 0;
        this->clear();

        if ( text == NULL || *text == ConstChar<Type>::StrZero )
            return;

        Type lookForQuote = 0;
        Type tokBuffer[MAX_CMD_STRING] = {0};

        for( ; *text != ConstChar<Type>::StrZero; text++ ) {
            if ( lookForQuote ) {
                if ( *text == lookForQuote ) {
                    tokBuffer[bufPos] = ConstChar<Type>::StrZero;
                    append( tokBuffer );
                    bufPos = 0;
                    lookForQuote = 0;
                    continue;
                }
                tokBuffer[bufPos++] = *text;
                continue;
            } else if ( TIsSpace(*text) ) {
                // skip rest of whitespaces
                while( TIsSpace(*(text+1)) ) text++;

                if (bufPos) {
                    tokBuffer[bufPos] = ConstChar<Type>::StrZero;
                    append( tokBuffer );
                    bufPos = 0;
                }
            } else if ( *text == ConstChar<Type>::Quote || *text == ConstChar<Type>::SingleQuote ) {
                lookForQuote = *text;
                if (bufPos) {
                    tokBuffer[bufPos] = ConstChar<Type>::StrZero;
                    append( tokBuffer );
                    bufPos = 0;
                }
                continue;
            } else {
                tokBuffer[bufPos++] = *text;
                continue;
            }
        }
        if ( lookForQuote || bufPos ) {
            tokBuffer[bufPos] = ConstChar<Type>::StrZero;
            append( tokBuffer );
        }
    }

    typedef TCmdArgs<char>      CmdArgs;
    typedef TCmdArgs<wchar_t>   WCmdArgs;

}   // ::inf

#endif // TCmdArgs_h__
